import { createContext, FC, ReactElement, useCallback, useMemo, useState } from "react";
import { produce } from "immer";

import ScopeItem from "./ScopeItem";

export const KeepAliveContext = createContext<{
	cacheDispatch: (arg: any) => void;
	hasAliveStatus: (arg: string) => {
		isKeep: boolean;
		status?: Status;
	};
	destroyCache: (arg: any) => void;
} | null>(null);
const { Provider } = KeepAliveContext;

export interface CacheDispatchOptions {
	action: "ACTION_CREATE" | "ACTION_UPDATE" | "ACTION_ACTIVE" | "ACTION_UNACTIVE";
	payload: {
		cacheId: string;
		children?: ReactElement;
		loadElement?: (arg: HTMLDivElement) => void;
	};
}

export enum Status {
	"ACTION_CREATE" = "create" /* 创建缓存 */,
	"ACTION_ACTIVE" = "active" /* 缓存激活 */,
	"ACTION_UPDATE" = "update" /* 更新组件 */,
	"ACTION_UNACTIVE" = "unActive" /* 缓存休眠 */
}

type CacheList = {
	cacheId: string;
	status: Status;
	children?: ReactElement;
	loadElement?: (arg: HTMLDivElement) => void;
}[];
const Scope: FC<{ children: ReactElement }> = props => {
	const { children } = props;
	const [cacheList, setCacheList] = useState<CacheList>([]);

	const hasAliveStatus = useCallback(
		(cacheId: string) => {
			const cacheIds = cacheList.map(v => v.cacheId);
			return {
				isKeep: cacheIds.includes(cacheId),
				status: cacheList.find(v => v.cacheId === cacheId)?.status
			};
		},
		[cacheList]
	);

	const cacheDispatch = useCallback((options: CacheDispatchOptions) => {
		const { action, payload } = options;
		const { cacheId, loadElement, children } = payload;
		if (Status[action] === "create") {
			setCacheList(
				produce(draft => {
					draft.push({
						cacheId,
						status: Status[action],
						loadElement,
						children
					});
				})
			);
		}

		if (Status[action] === "active") {
			setCacheList(
				produce(draft => {
					draft.forEach(v => {
						if (v.cacheId === cacheId) {
							v.status = Status[action];
							v.loadElement = loadElement;
						}
					});
				})
			);
		}

		if (Status[action] === "update") {
			setCacheList(
				produce(draft => {
					draft.forEach(v => {
						if (v.cacheId === cacheId) {
							v.children = children!;
						}
					});
				})
			);
		}

		if (Status[action] === "unActive") {
			setCacheList(
				produce(draft => {
					draft.forEach(v => {
						if (v.cacheId === cacheId) {
							v.status = Status[action];
						}
					});
				})
			);
		}
	}, []);

	const destroyCache = useCallback((cacheId: string) => {
		setCacheList(
			produce(draft => {
				draft.filter(v => v.cacheId !== cacheId);
			})
		);
	}, []);

	const contextValue = useMemo(() => {
		return {
			cacheDispatch,
			hasAliveStatus,
			destroyCache
		};
	}, [cacheDispatch, destroyCache, hasAliveStatus]);

	return (
		<Provider value={contextValue}>
			{children}
			{cacheList.map(v => {
				return <ScopeItem {...v} dispatch={cacheDispatch} key={v.cacheId}></ScopeItem>;
			})}
		</Provider>
	);
};

export default Scope;
